
/**
	Compile with lemon.
*/

%start_symbol module

%token_prefix T_
%token_type {moses::Item*}
%extra_argument {moses::ParseState *extra}

%syntax_error {
	++extra->errors;
	fprintf(stderr, "Error at line %d\n", lines_vb);
}

%parse_accept {
	fprintf(stderr, "Parser accepted. There were %d errors\n", extra->errors);
}

%parse_failure {
	fprintf(stderr, "failed %d\n", lines_vb);
}


%include {
#include <cstring>
#include <string>
#include <iostream>
#include <utility>
#include <deque>
#include <cassert>
#include "Ast.h"
#include "MosParser.h"

using namespace moses;

extern char* yytext;
extern std::string oldp;
extern std::string stringBuffer;
extern std::deque<std::string> strQueue;
extern std::deque<std::string> strStack;
extern int lines_vb;

}

/* lowest */
/* = += *= /= %=	right to left */
/* ?:				right to left */
/* ||				left to right */
/* &&				left to right */
/* |				left to right */
/* ^				left to right */
/* &				left to right */
/* == !=			left to right */
/* < > <= >=		left to right */
/* << >>			left to right */
/* + -				left to right */
/* * / %			left ro right */
/* (type cast) new	left ro right */
/* ++(post) -- ! -	right to left */
/* ++(pre) --		right to left */
/* ( ) [ ] .		left to right */
/* highest */

%left		PLUS MINUS.
%left		MUL DIV.
%left		NEG.
%left		LPAREN RPAREN LBRACKET RBRACKET.

module(M)			::= funcs(FS).												{ M = extra->pTree = new Module((ItemList<Function>*)FS); }

funcs(FS)			::= funcs(FS1) func(F).										{ ((ItemList<Function>*)FS1)->push_back((Function*)F); FS = FS1; }
funcs(FS)			::= .														{ FS = new ItemList<Function>; }
func(F)				::= identifier(I) COLONCOLON params(AS) 
						funcrows(FS).											{ F = new Function((Identifier*)I, (ItemList<Type>*)AS, (ItemList<FunctionRow>*)FS); }
						
params(PS)			::= paramsA(PSA).											{ PS = PSA; }
params(PS)			::= .														{ PS = new ItemList<Type>; }
paramsA(PS)			::= paramsA(PS1) COMMA type(T).								{ ((ItemList<Type>*)PS1)->push_back((Type*)T); PS = PS1; }
paramsA(PS)			::= type(T).												{ PS = new ItemList<Type>; ((ItemList<Type>*)PS)->push_back((Type*)T); }

funcrows(RS)		::= funcrows(RS1) funcrow(R).								{ ((ItemList<FunctionRow>*)RS1)->push_back((FunctionRow*)R);RS = RS1; }
funcrows(RS)		::= funcrow(R).												{ RS = new ItemList<FunctionRow>; ((ItemList<FunctionRow>*)RS)->push_back((FunctionRow*)R); }
funcrow(R)			::= COLON identifier(I) patterns(PS) ASSIGN expr(E).		{ R = new FunctionRow((Identifier*)I, (ItemList<Pattern>*)PS, (Expr*)E); }

expr(E)				::= expr(L)		PLUS	expr(R).							{ E = new BinaryExpr((Expr*)L,	T_PLUS, 	(Expr*)R); }
expr(E)				::= expr(L)		MINUS	expr(R).							{ E = new BinaryExpr((Expr*)L,	T_MINUS,	(Expr*)R); }
expr(E)				::= expr(L)		MUL		expr(R).							{ E = new BinaryExpr((Expr*)L,	T_MUL,  	(Expr*)R); }
expr(E)				::= expr(L)		DIV		expr(R).							{ E = new BinaryExpr((Expr*)L,	T_DIV,  	(Expr*)R); }
expr(E)				::=				MINUS	expr(L). [NEG]						{ E = new UnaryExpr((Expr*)L,	T_MINUS); }
expr(E)				::= LPAREN expr(L) RPAREN.									{ E = L; }
expr(E)				::= literal(L).												{ E = L; }
expr(E)				::= identifier(I) LPAREN args(AS) RPAREN.					{ E = new Call((Identifier*)I, (ItemList<Expr>*)AS); }

args(AS)			::= argsA(ASA).												{ AS = ASA; }
args(AS)			::= .														{ AS = new ItemList<Expr>; }
argsA(AS)			::= argsA(AS1) COMMA expr(E).								{ ((ItemList<Expr>*)AS1)->push_back((Expr*)E); AS = AS1; }
argsA(AS)			::= expr(E).												{ AS = new ItemList<Expr>; ((ItemList<Expr>*)AS)->push_back((Expr*)E); }

patterns(PS)		::= patterns(PS1) pattern(P).								{ ((ItemList<Pattern>*)PS1)->push_back((Pattern*)P); PS = PS1; }
patterns(PS)		::= .														{ PS = new ItemList<Pattern>; }
pattern(P)			::= literal(L).												{ P = new LiteralPattern((Literal*)L); }
pattern(P)			::= UNDERSCORE.												{ P = new ConstPattern(true); }
pattern(P)			::= LBRACKET pattern(P1) RBRACKET.							{ P = P1; /* TODO: */ }

identifier(I)		::= IDENTIFIER.												{ I = new Identifier(oldp); }
type(T)				::= TYPE_BYTE.												{ T = new Type(Type::INT); }
type(T)				::= TYPE_CHAR.												{ T = new Type(Type::INT); }
type(T)				::= TYPE_INT.												{ T = new Type(Type::INT); }
type(T)				::= TYPE_FLOAT.												{ T = new Type(Type::FLOAT); }
type(T)				::= LBRACKET type(T1) RBRACKET.								{ T = T1; }

literal(L)			::= LITERAL_INTEGER.										{ L = new Literal(Value(atoi(oldp.c_str()))); }
literal(L)			::= LITERAL_FLOAT.											{ L = new Literal(Value((float)atof(oldp.c_str())));; }
/*

document(D)			::= sets(SS) DOCUMENT LCURL args(AS) RCURL paragraphs(PS) sections(SS1).	{ D = extra->pTree = new Document((ItemList<Stmnt>*)SS, (ItemList<Expr>*)AS, (ItemList<Stmnt>*)PS, (ItemList<Section>*)SS1); }

sections(SS)		::= sections(SS1) section(S).								{ ((ItemList<Section>*)SS1)->push_back((Section*)S); SS = SS1; }
sections(SS)		::= .														{ SS = new ItemList<Section>; }
section(S)			::= SECTION LCURL args(AS) RCURL paragraphs(PS) headings(HS).	{ S = new Section(Section::SECTION, (ItemList<Expr>*)AS, (ItemList<Stmnt>*)PS, (ItemList<Section>*)HS); }

headings(HS)		::= headings(HS1) heading(H).								{ ((ItemList<Heading>*)HS1)->push_back((Heading*)H); HS = HS1; }
headings(HS)		::= .														{ HS = new ItemList<Section>; }
heading(H)			::= hlevel(HL) LCURL args(AS) RCURL paragraphs(PS).			{ H = new Section((Section::Level)int(HL), (ItemList<Expr>*)AS, (ItemList<Stmnt>*) PS, new ItemList<Section>); }

hlevel(HL)			::= HEADING1.												{ HL = (Item*)Section::HEADING1; }
hlevel(HL)			::= HEADING2.												{ HL = (Item*)Section::HEADING2; }
hlevel(HL)			::= HEADING3.												{ HL = (Item*)Section::HEADING3; }

paragraphs(PS)		::= paragraphs(PS1) paragraph(P).							{ ((ItemList<Stmnt>*)PS1)->push_back((Stmnt*)P); PS = PS1; }
paragraphs(PS)		::= .														{ PS = new ItemList<Stmnt>; }
paragraph(P)		::= words(WS) EOP.											{ P = new JustifiedParagraph((ItemList<Expr>*)WS); }
paragraph(P)		::= command(C).												{ P = C; }
paragraph(P)		::= PRETEXT.												{ P = new PreformattedParagraph(strQueue.front()); strQueue.pop_front(); }

//commands(CS)		::= commands(CS1) command(C).								{ CS; CS1; C; }
//commands(CS)		::= .														{ CS; }
command(C)			::= set(S).													{ C = S; }
command(C)			::= contents(C1).											{ C = C1; }
//command(C)			::= SYMBOL LCURL RCURL.									{ C = C1; }

sets(SS)			::= sets(SS1) set(S).										{ ((ItemList<Stmnt>*)SS1)->push_back((Stmnt*)S); SS = SS1; }
sets(SS)			::= .														{ SS = new ItemList<Stmnt>; }
set(S)				::= SET LCURL identifier(I) COMMA expr(E) RCURL.			{ S = new Set((Identifier*)I, (Expr*)E); }

words(WS)			::= words(WS1) word(W).										{ ((ItemList<Expr>*)WS1)->push_back((Expr*)W); WS = WS1; }
words(WS)			::= .														{ WS = new ItemList<Expr>; }
word(W)				::= WORD.													{ W = new Word(strQueue.front()); strQueue.pop_front(); }
word(W)				::= call(C).												{ W = C; }


expr(E)				::= expr(L)		PLUS	expr(R).							{ E = new BinaryExpr((Expr*)L, T_PLUS, (Expr*)R); }
expr(E)				::= expr(L)		MINUS	expr(R).							{ E = new BinaryExpr((Expr*)L, T_MINUS, (Expr*)R); }
expr(E)				::= expr(L)		MUL		expr(R).							{ E = new BinaryExpr((Expr*)L, T_MUL, (Expr*)R); }
expr(E)				::= expr(L)		DIV		expr(R).							{ E = new BinaryExpr((Expr*)L, T_DIV, (Expr*)R); }
expr(E)				::=				MINUS	expr(L). [NEG]						{ E = new UnaryExpr((Expr*)L, T_MINUS); }

expr(E)				::= LPAREN expr(L) RPAREN.									{ E = L; }

expr(E)				::= DEC_INTEGER.											{ E = new Literal(Value(atoi(oldp.c_str()))); }
expr(E)				::= DEC_FLOAT.												{ E = new Literal(Value((float)atof(oldp.c_str()))); }
expr(E)				::= STRING_LIT.												{ E = new Literal(Value(strQueue.front())); strQueue.pop_front(); }
expr(E)				::= identifier(I).											{ E = I; }

expr(E)				::= call(C).												{ E = C; }

call(C)				::= SYMBOLCALL LCURL args(AS) RCURL.						{ C = new SymbolCall(strStack.back(), (ItemList<Expr>*)AS); strStack.pop_back(); }
identifier(I)		::= IDENTIFIER.												{ I = new Identifier(oldp); }

contents(C)			::= CONTENTS LCURL args(AS) RCURL.							{ C = new Contents((ItemList<Expr>*)AS); }

args(AS)			::= argsA(ASA).												{ AS = ASA; }
args(AS)			::= .														{ AS = new ItemList<Expr>; }
argsA(AS)			::= argsA(AS1) COMMA expr(E).								{ ((ItemList<Expr>*)AS1)->push_back((Expr*)E); AS = AS1; }
argsA(AS)			::= expr(E).												{ AS = new ItemList<Expr>; ((ItemList<Expr>*)AS)->push_back((Expr*)E); }
*/
/*
//=============================================================================
// Document
//=============================================================================

document(P) 		::= stmnts(SS).
{
	P = extra->pTree = new Document((ItemList<Stmnt>*)SS);
}

//=============================================================================
// Statements
//=============================================================================
stmnts(SS)			::= stmnts(SS1) stmnt(S).				{
	( (ItemList<Item>*)SS1 )->push_back( (Item*)S );
	SS = SS1;
}

stmnts(SS)			::= .									{ SS = new ItemList<Item>; }

stmnt(S) 			::= section(S1).						{ S = S1; }
stmnt(S)			::= command(C).							{ S; C; }

//stmnt(S) 			::= SYMBOL args(AS).					{ S = new SymbolCall(strQueue.front(), (ItemList<Expr>*)AS); strQueue.pop_front(); }
//stmnt(S) 			::= LCURL expr(I) RCURL.				{ S = new Var((Expr*)I); }

command(C)			::= SET LCURL ident(I) COMMA expr(E) RCURL.	{ C = new Set((Identifier*)I, (Expr*)E); }

//=============================================================================
// Sections, headings and paragraphs
//=============================================================================
section(SC)			::=	SECTION LCURL text(T) RCURL paras(PS) headings(HS).
						{ SC = new Section((ItemMap*)0, (ItemList<Expr>*)T, (ItemList<Paragraph>*)PS, (ItemList<Heading>*)HS); }

sectionopts(SOS)	::= sectionopts(SOS1) sectionopt(SO).
						{ ((ItemMap*)SOS1)->setExpr(((Option*)SO)->first, ((Option*)SO)->second); SOS = SOS1; }
sectionopts(SOS)	::= .									{ SOS = new ItemMap; }
sectionopt(SO)		::= AUTHOR LCURL expr(E) RCURL.			{ SO = (Item*)new Option("author", (Expr*)E); }


headings(HS)		::= headings(HS1) heading(H).			{ ((ItemList<Heading>*)HS1)->push_back((Heading*)H); HS = HS1; }
headings(HS)		::= .									{ HS = new ItemList<Heading>; }
heading(H)			::= hlevel(HL) LCURL text(T) RCURL paras(PS).	{ H = new Heading((int)HL, (ItemList<Expr>*)T, (ItemList<Paragraph>*)PS); }

hlevel(HL)			::= HEADING1.							{ HL = (Item*)1; }
hlevel(HL)			::= HEADING2.							{ HL = (Item*)2; }
hlevel(HL)			::= HEADING3.							{ HL = (Item*)3; }
hlevel(HL)			::= HEADING4.							{ HL = (Item*)4; }
hlevel(HL)			::= HEADING5.							{ HL = (Item*)5; }
hlevel(HL)			::= HEADING6.							{ HL = (Item*)6; }
hlevel(HL)			::= HEADING7.							{ HL = (Item*)7; }
hlevel(HL)			::= HEADING8.							{ HL = (Item*)8; }
hlevel(HL)			::= HEADING9.							{ HL = (Item*)9; }

paras(PS)			::= paras(PS1) para(P).					{ ((ItemList<Stmnt>*)PS1)->push_back((Stmnt*)P); PS = PS1; }
paras(PS)			::= .									{ PS = new ItemList<Stmnt>; }
para(P)				::= entities(ES).						{ P = new Paragraph((ItemList<Expr>*)ES); }
para(P)				::= command(C).							{ P = C; }
//para(P)				::= PRETEXT.						{ P = new Paragraph(new Text(strQueue.front()), Paragraph::Pre); strQueue.pop_front(); }

entities(ES)		::= entities(ES1) entity(E).			{ ((ItemList<Expr>*)ES1)->push_back((Expr*)E); ES = ES1; }
entities(ES)		::= .									{ ES = new ItemList<Expr>; }
entity(E)			::= WORD.								{ E = new Word(oldp); }


//=============================================================================
// Expressions
//=============================================================================
expr(E)				::= expr(L)		PLUS	expr(R).		{ E = new BinaryExpr((Expr*)L, T_PLUS, (Expr*)R); }
expr(E)				::= expr(L)		MINUS	expr(R).		{ E = new BinaryExpr((Expr*)L, T_MINUS, (Expr*)R); }
expr(E)				::= expr(L)		MUL		expr(R).		{ E = new BinaryExpr((Expr*)L, T_MUL, (Expr*)R); }
expr(E)				::= expr(L)		DIV		expr(R).		{ E = new BinaryExpr((Expr*)L, T_DIV, (Expr*)R); }
expr(E)				::=				MINUS	expr(L). [NEG]	{ E = new UnaryExpr((Expr*)L, T_MINUS); }

expr(E)				::= LPAREN expr(L) RPAREN.				{ E = L; }

expr(E)				::= DEC_INTEGER.						{ E = new Literal(Value((float)atoi(oldp.c_str()))); }
expr(E)				::= DEC_FLOAT.							{ E = new Literal(Value((float)atof(oldp.c_str()))); }
expr(E)				::= STRING_LIT.							{ E = new Literal(Value(strQueue.front())); strQueue.pop_front(); }
expr(E)				::= ident(I).							{ E = I; }

expr(E)				::= call(C).							{ E = C; }

//=============================================================================
// Misc
//=============================================================================
ident(I)			::= IDENTIFIER.							{ I = new Identifier(oldp); }
text(T)				::= entities(ES).						{ T = ES; }

call(C)				::= SYMBOL LCURL args(AS) RCURL.		{ C = new SymbolCall(strQueue.front(), (ItemList<Expr>*)AS); strQueue.pop_front(); }

args(AS)			::= argsA(ASA).							{ AS = ASA; }
args(AS)			::= .									{ AS = new ItemList<Expr>; }
argsA(AS)			::= argsA(AS1) COMMA expr(E).			{ ((ItemList<Expr>*)AS1)->push_back((Expr*)E); AS = AS1; }
argsA(AS)			::= expr(E).							{ AS = new ItemList<Expr>; ((ItemList<Expr>*)AS)->push_back((Expr*)E); }
*/
